/*
 * Moussavi_1.7.c
 *
 * Created: 3/12/2011 1:04:38 PM
 *  Author: David
 */ 

#include "Moussavi_Internals.h"


volatile uint8_t	g_iPORTB_Buf = 0;
volatile uint8_t	g_iPORTC_Buf = 0;
volatile uint8_t	g_iPORTD_Buf = 0;
volatile uint8_t	g_iPORTF_Buf = 0;
volatile uint8_t	Line_Buff1[48];
volatile uint8_t	Line_Buff2[48];
volatile uint8_t* 	g_iPWM_Seq_Active = NULL;
volatile uint8_t* 	g_iPWM_Seq_NotActive = NULL;

volatile uint16_t	g_iWidthDepenantDelay = 0x1b58;		// as init value set 3.5msec
volatile uint32_t	g_iHeadSweepTime_USEC = 800000;		// 0.8 seconds
volatile uint32_t	g_iNumOfPicsInSweep = 2;			// Number of pictures we
														// want to see in single head
														// sweeping of viewer
volatile uint32_t	g_iTicks_8prescale_perUsec = 2;		// we are on 16 MHz -> 16/8 ticks


volatile uint8_t	g_iFlashRead = 48;		// Flash needs reading
volatile uint16_t	g_iTimer0OvfCounter = 0;
volatile uint8_t	g_iCurrentFrameCycle = 0;
volatile uint8_t	g_iCurrentFrameWidth = 255;
volatile uint8_t	g_iInnerCounter = 0;
volatile uint8_t	g_iCurrentFrame = 0;
volatile uint32_t	g_iStartingAddress = 0;
volatile uint32_t	g_iCurrentAddress = 0;

volatile FileEntry_ST 	g_sCurrentFileInfo;

volatile uint8_t	g_iRowNum;
volatile uint8_t 	g_iPWM_Counter;

extern uint8_t		g_isOperating;
extern uint8_t		bFS_Empty;


//==============================================================================================
void Anibike_InitLeds ( void )
{
	// Direction of rows
	DDRA  = 0b11111111;
	PORTA = 0b00000000;

	PORTB&= 0b00001111;
	DDRB &= 0b00001111;

	PORTC = 0b00000000;
	DDRC  = 0b00000000;

	PORTD = 0b00000000;
	DDRD  = 0b11000000;

	PORTF = 0b00000000;
	DDRF  = 0b00000000;

}

//==============================================================================================
void Moussavi_InitAll (void)
{
	UNSET_BUFFERREADY;

	// enabe the usb voltage regulator - It gives our flash 3.3V
	UHWCON |= (1 << UVREGE);

	// Init the SPI flash device
	dataflash_spi_init( );	

	// Init LEDs
	Anibike_InitLeds ( );


	// CTC mode timer between columns	
	TCCR1B = (1<<WGM12);	// Enable CTC Mode
	TIMSK1 = (1<<OCIE1A);	// Compare Interrupt
	OCR1A = g_iWidthDepenantDelay;	// =3.5 msec   0xea5f=10msec
	TCNT1 = 0x0000;
	TCCR1B |= (1<<CS11);	// Prescale 8
	
	// CTC mode timer for PWM counter
	TCCR2B = (1<<WGM22); 	// Enable CTC Mode
	TIMSK2 = (1<<OCIE2A); 	// Compare interrupt
	OCR2A = 0x46;			// =35usec
	TCNT2 = 0x00;
	TCCR2B = (1<<CS21); 	// Prescalar 8

	// The buffer pointers setting
	g_iPWM_Seq_Active = Line_Buff1;
	g_iPWM_Seq_NotActive = Line_Buff2;
	
	g_iFlashRead = 48;	// Flash needs reading

	SET_ROW(0);
	ROW_PATTERN = 1;

	// USB Init
	usb_init();
    hw_init();

    // init the class driver here
    cdc_init();

    // register the rx handler function with the cdc
    cdc_reg_rx_handler(rx);

	g_isOperating = 1;
}

int main(void)
{
	uint8_t iCurrByte = 0;
	uint8_t iTemp = 0;

	SET_FIRST_BUFFER;

	//================================================
	//////////////// INITIALIZATIONS /////////////////
	//================================================
	Moussavi_InitAll ();

	sei (); 

	//================================================
	////////////////// OPERATIONAL ///////////////////
	//================================================
	for (;; usb_poll()/*19cc*/)
	{	

		if ( !g_isOperating )
		{
			continue;
		}

		// Advance Row Number
		ADVANCE_ROW;

		if (ROW_NUM==0) 		// 5cc
		{
			ADVANCE_COUNTER;
		}


		asm ( "call PrepareBuffers" );			// 15usec	
		
		// Buffers Ready flag
		SET_BUFFERREADY;						// 2cc
		

		// Next Memory Lines Read
		while  ((BUFFER_IS_READY) && g_iFlashRead)
		{
			// Read next memory slots
			READ_FLASH_BYTE;

			iCurrByte = 48-g_iFlashRead;
			iTemp = SPDR;
				
			if ( (WHICH_BUFFER) == 0 )
			{
				Line_Buff2[iCurrByte] = iTemp;
			}
			else
			{
				Line_Buff1[iCurrByte] = iTemp;	
			}

			g_iFlashRead --;
		}

		// Wait for next request
		while ( BUFFER_IS_READY ) {usb_poll();}
	}

}





//==============================================================================================
//
//  Interrupt Procesing Code
//
//==============================================================================================

// Interrupt for changing single line
//==============================================================================================
ISR (TIMER1_COMPA_vect)
{
	unsigned char adrByte1, adrByte2, adrByte3;

	ROW_PORT = 0;
	ROW_PATTERN = 0;
	TCNT1 = 0x0000;

	// Advance the current column
	g_iInnerCounter++;
	if ( g_iInnerCounter >= g_iCurrentFrameWidth ) // if we reached to the end of the pic
	{
		CS_UP;
		g_iInnerCounter = 0;
		
		g_iCurrentFrameCycle --;	// decrease the projection time

//		g_iCurrentFrame ++;
//		if ( g_sCurrentFileInfo.iNumFrames <= g_iCurrentFrame )
		g_iCurrentFrame = 0;

		g_iStartingAddress = (uint32_t)(g_sCurrentFileInfo.iBlockList[g_iCurrentFrame]) * (uint32_t)(FS_FRAME_CAP);
		g_iCurrentAddress = g_iStartingAddress;
		
		adrByte1 = (g_iCurrentAddress>>16)&0xff;
		adrByte2 = (g_iCurrentAddress>>8)&0xff;
		adrByte3 = g_iCurrentAddress&0xff;  

		CS_DOWN;

		SPDR = READ_ARRAY;
		while (! (SPSR & (1<<SPIF))) {}
		SPDR = adrByte1;
		while (! (SPSR & (1<<SPIF))) {}
		SPDR = adrByte2;
		while (! (SPSR & (1<<SPIF))) {}
		SPDR = adrByte3;
		while (! (SPSR & (1<<SPIF))) {}
	}

	// Frame managing stuff
	if ( g_iCurrentFrameCycle == 0 )
	{	// just finished a cycle

		// prepare next file projection
		// ============================
			
		// read next 
		if ( FS_ReadNextEntry ( &g_sCurrentFileInfo ) )
		{
			CS_UP;
			g_iCurrentFrameCycle = g_sCurrentFileInfo.Reserved1;

			// start reading first frame
			g_iCurrentFrame = 0;
			g_iStartingAddress = (uint32_t)(g_sCurrentFileInfo.iBlockList[0]) * (uint32_t)(FS_FRAME_CAP);
			g_iCurrentAddress = g_iStartingAddress;
			g_iInnerCounter = 0;
			g_iCurrentFrameWidth = g_sCurrentFileInfo.Reserved2;

			// Calculate the Compare value
			g_iWidthDepenantDelay = 
					g_iHeadSweepTime_USEC/(g_iNumOfPicsInSweep*g_iCurrentFrameWidth)*g_iTicks_8prescale_perUsec;

			OCR1A = g_iWidthDepenantDelay>>3;

			adrByte1 = (g_iCurrentAddress>>16)&0xff;
			adrByte2 = (g_iCurrentAddress>>8)&0xff;
			adrByte3 = g_iCurrentAddress&0xff;  
			CS_DOWN;

			SPDR = READ_ARRAY;
			while (! (SPSR & (1<<SPIF))) {}
			SPDR = adrByte1;
			while (! (SPSR & (1<<SPIF))) {}
			SPDR = adrByte2;
			while (! (SPSR & (1<<SPIF))) {}
			SPDR = adrByte3;
			while (! (SPSR & (1<<SPIF))) {}
		}
	}


	// Switch Buffers
	if ( WHICH_BUFFER == 0 )
	{
		SET_SECOND_BUFFER;
	}
	else
	{
		SET_FIRST_BUFFER;
	}

	g_iFlashRead = 48;		// Flash needs reading
	
	TCNT1 = 0x0000;

	SET_ROW(0);
	ROW_PATTERN = 1;
	PWM_COUNTER = 0;
}


// Interrupt for PWM timing
//==============================================================================================
ISR (TIMER2_COMPA_vect, ISR_NAKED)		// Takes 2 usec
{
	asm ( "push r1" );
	asm ( "push r0" );
	asm ( "in r0, 0x3f" );				// Store the status register
	asm ( "push r0" );
	asm ( "clr r1" ); 					// Clear register

	asm ( "push r24" );	
	asm ( "push r25" );

	asm ( "in	r24, 0x04" );			// Load the contants of DDRB
	asm ( "andi	r24, 0x0F" );			// Make and with 0x0F
	asm ( "out	0x04, r24" );			// Update DDRB

	asm ( "out	0x07, r1" );			// Update DDRC to be 0

	asm ( "in	r24, 0x0A" );			// Load the contants of DDRD
	asm ( "andi	r24, 0xC3" );			// Make and with 0b00111100
	asm ( "out	0x0A, r24" );			// Update DDRD
	
	asm ( "out	0x10, r1" );			// Update DDRF to be 0

	asm ( "out	0x02, r1" );			// Update PORTA to be 0

	// Manipulate DDRB
	asm ( "lds	r25, g_iPORTB_Buf" );
	asm ( "in	r24, 0x04" );
	asm ( "or	r24, r25" );
	asm ( "out	0x04, r24" );

	// Manipulate DDRC
	asm ( "lds	r25, g_iPORTC_Buf" );
	asm ( "out	0x07, r25" );

	// Manipulate DDRD
	asm ( "lds	r25, g_iPORTD_Buf" );
	asm ( "in	r24, 0x0A" );
	asm ( "or	r24, r25" );
	asm ( "out	0x0A, r24" );

	// Manipulate DDRF
	asm ( "lds	r25, g_iPORTF_Buf" );
	asm ( "out	0x10, r25" );

	PORTA = ROW_PATTERN;
	
	// Store 0 to g_iBuffersReady
	UNSET_BUFFERREADY;

	asm ( "pop r25" );
	asm ( "pop r24" );

	asm ( "pop r0" );
	asm ( "out 0x3F,r0" );
	asm ( "pop r0" );
	asm ( "pop r1" );
	TCNT2 = 0x00;

	reti ();
}


